<template>
  <Tooltip placement="top">
    <template #title>
      <span>{{ t("component.table.settingColumn") }}</span>
    </template>
    <Popover
      placement="bottomLeft"
      trigger="click"
      @open-change="onOpenChange"
      :overlayClassName="`${prefixCls}__column-list`"
      :getPopupContainer="getPopupContainer"
    >
      <template #title>
        <div :class="`${prefixCls}__popover-title`">
          <Checkbox
            :indeterminate="indeterminate"
            v-model:checked="isColumnAllSelected"
            @change="onColumnAllSelectChange"
          >
            {{ t("component.table.settingColumnShow") }}
          </Checkbox>

          <Checkbox
            v-model:checked="isIndexColumnShow"
            @change="onIndexColumnShowChange"
          >
            {{ t("component.table.settingIndexColumnShow") }}
          </Checkbox>
          <!-- 设置了 rowSelection 才出现 -->
          <Checkbox
            v-model:checked="isRowSelectionShow"
            @change="onRowSelectionShowChange"
            v-if="defaultIsRowSelectionShow"
          >
            {{ t("component.table.settingSelectColumnShow") }}
          </Checkbox>

          <a-button size="small" type="link" @click="onReset">
            {{ t("common.resetText") }}
          </a-button>
        </div>
      </template>

      <template #content>
        <ScrollContainer>
          <Checkbox.Group
            v-model:value="columnCheckedOptions"
            ref="columnOptionsRef"
          >
            <template v-for="opt in columnOptions" :key="opt.value">
              <div :class="`${prefixCls}__check-item`" :data-no="opt.value">
                <DragOutlined class="table-column-drag-icon" />
                <Checkbox :value="opt.value">
                  {{ opt.label }}
                </Checkbox>

                <Tooltip
                  placement="bottomLeft"
                  :mouseLeaveDelay="0.4"
                  :getPopupContainer="getPopupContainer"
                >
                  <template #title>
                    {{ t("component.table.settingFixedLeft") }}
                  </template>
                  <Icon
                    icon="line-md:arrow-align-left"
                    :class="[
                      `${prefixCls}__fixed-left`,
                      {
                        active: opt.fixed === 'left',
                        disabled: opt.value
                          ? !columnCheckedOptions.includes(opt.value)
                          : true,
                      },
                    ]"
                    @click="onColumnFixedChange(opt, 'left')"
                  />
                </Tooltip>
                <Divider type="vertical" />
                <Tooltip
                  placement="bottomLeft"
                  :mouseLeaveDelay="0.4"
                  :getPopupContainer="getPopupContainer"
                >
                  <template #title>
                    {{ t("component.table.settingFixedRight") }}
                  </template>
                  <Icon
                    icon="line-md:arrow-align-left"
                    :class="[
                      `${prefixCls}__fixed-right`,
                      {
                        active: opt.fixed === 'right',
                        disabled: opt.value
                          ? !columnCheckedOptions.includes(opt.value)
                          : true,
                      },
                    ]"
                    @click="onColumnFixedChange(opt, 'right')"
                  />
                </Tooltip>
              </div>
            </template>
          </Checkbox.Group>
        </ScrollContainer>
      </template>
      <SettingOutlined />
    </Popover>
  </Tooltip>
</template>
<script lang="ts" setup>
import type {
  BasicColumn,
  ColumnOptionsType,
  ColumnChangeParam,
} from "../../types/table";
import {
  ref,
  nextTick,
  unref,
  computed,
  useAttrs,
  watch,
  onMounted,
} from "vue";
import { Tooltip, Popover, Checkbox, Divider } from "ant-design-vue";
import type { CheckboxChangeEvent } from "ant-design-vue/lib/checkbox/interface";
import { SettingOutlined, DragOutlined } from "@ant-design/icons-vue";
import Icon from "@/components/Icon/Icon.vue";
import { ScrollContainer } from "@/components/Container";
import { useI18n } from "@/hooks/web/useI18n";
import { useTableContext } from "../../hooks/useTableContext";
import { useDesign } from "@/hooks/web/useDesign";
import { isFunction, isNil } from "@/utils/is";
import { getPopupContainer as getParentContainer } from "@/utils";
import { cloneDeep, omit } from "lodash-es";
import Sortablejs from "sortablejs";
import { INDEX_COLUMN_FLAG } from "@/components/Table/src/const";

// 列表设置缓存
import { useTableSettingStore } from "@/store/modules/tableSetting";
import { useRoute } from "vue-router";
import { TableRowSelection } from "@/components/Table/src/types/table";

const tableSettingStore = useTableSettingStore();

defineOptions({ name: "ColumnSetting" });
const emit = defineEmits(["columns-change"]);

const route = useRoute();

const { t } = useI18n();
const { prefixCls } = useDesign("basic-column-setting");

const attrs = useAttrs();
const table = useTableContext();

const props = withDefaults(
  defineProps<{
    /**
     * 是否缓存列的设置
     */
    cache?: boolean;
  }>(),
  {
    cache: () => false,
  },
);

const getPopupContainer = () => {
  return isFunction(attrs.getPopupContainer)
    ? attrs.getPopupContainer()
    : getParentContainer();
};

// 默认值
let defaultIsIndexColumnShow: boolean = false;
let defaultIsRowSelectionShow: boolean = false;
let defaultRowSelection: TableRowSelection<Recordable<any>>;
let defaultColumnOptions: ColumnOptionsType[] = [];

// 是否已经从缓存恢复
let isRestored = false;
let isInnerChange = false;

// 列可选项
const columnOptions = ref<ColumnOptionsType[]>([]);
const columnOptionsRef = ref(null);
// 已选列
const columnCheckedOptions = ref<string[]>([]);
// 已选变化
watch(columnCheckedOptions, () => {
  // 恢复缓存后生效
  if (isRestored) {
    // 显示
    columnOptions.value
      .filter((o) => columnCheckedOptions.value.includes(o.value))
      .forEach((o) => {
        o.column.defaultHidden = false;
      });
    // 隐藏
    columnOptions.value
      .filter((o) => !columnCheckedOptions.value.includes(o.value))
      .forEach((o) => {
        o.column.defaultHidden = true;
        o.fixed = undefined;
      });
    // 从 列可选项 更新 全选状态
    isColumnAllSelectedUpdate();

    // 列表列更新
    tableColumnsUpdate();
    // 更新列缓存
    props.cache && columnOptionsSave();
  }
});

// 全选
const isColumnAllSelected = ref<boolean>(false);
const onColumnAllSelectChange = () => {
  if (columnCheckedOptions.value.length < columnOptions.value.length) {
    columnCheckedOptions.value = columnOptions.value.map((o) => o.value);
  } else {
    columnCheckedOptions.value = [];
  }
};

// 半选状态
const indeterminate = computed(() => {
  return (
    columnCheckedOptions.value.length > 0 &&
    columnCheckedOptions.value.length < columnOptions.value.length
  );
});

// 是否显示序号列
const isIndexColumnShow = ref<boolean>(false);
// 序号列更新
const onIndexColumnShowChange = (e: CheckboxChangeEvent) => {
  // 更新 showIndexColumn
  showIndexColumnUpdate(e.target.checked);
  // 更新 showIndexColumn 缓存
  props.cache &&
    typeof route.name === "string" &&
    tableSettingStore.setShowIndexColumn(route.name, e.target.checked);
};

// 是否显示选择列
const isRowSelectionShow = ref<boolean>(false);
// 选择列更新
const onRowSelectionShowChange = (e: CheckboxChangeEvent) => {
  // 更新 showRowSelection
  showRowSelectionUpdate(e.target.checked);
  // 更新 showRowSelection 缓存
  props.cache &&
    typeof route.name === "string" &&
    tableSettingStore.setShowRowSelection(route.name, e.target.checked);
};

// 更新列缓存
const columnOptionsSave = () => {
  if (typeof route.name === "string") {
    // 按路由 name 作为缓存的key（若一个路由内存在多个表格，需自行调整缓存key来源）
    tableSettingStore.setColumns(route.name, columnOptions.value);
  }
};

// 重置
const onReset = () => {
  // 重置默认值
  isIndexColumnShow.value = defaultIsIndexColumnShow;
  // 序号列更新
  onIndexColumnShowChange({
    target: { checked: defaultIsIndexColumnShow },
  } as CheckboxChangeEvent);
  // 重置默认值
  isRowSelectionShow.value = defaultIsRowSelectionShow;
  // 选择列更新
  onRowSelectionShowChange({
    target: { checked: defaultIsRowSelectionShow },
  } as CheckboxChangeEvent);
  // 重置默认值
  columnOptions.value = cloneDeep(defaultColumnOptions);
  // 更新表单状态
  formUpdate();
};

// 设置列的 fixed
const onColumnFixedChange = (
  opt: ColumnOptionsType,
  type: "left" | "right",
) => {
  if (type === "left") {
    if (!opt.fixed || opt.fixed === "right") {
      opt.fixed = "left";
    } else {
      opt.fixed = undefined;
    }
  } else if (type === "right") {
    if (!opt.fixed || opt.fixed === "left") {
      opt.fixed = "right";
    } else {
      opt.fixed = undefined;
    }
  }

  // 列表列更新
  tableColumnsUpdate();
  // 更新列缓存
  props.cache && columnOptionsSave();
};

// 沿用逻辑
const sortableFix = async () => {
  // Sortablejs存在bug，不知道在哪个步骤中会向el append了一个childNode，因此这里先清空childNode
  // 有可能复现上述问题的操作：拖拽一个元素，快速的上下移动，最后放到最后的位置中松手
  if (columnOptionsRef.value) {
    const el = (columnOptionsRef.value as InstanceType<typeof Checkbox.Group>)
      .$el;
    Array.from(el.children).forEach((item) => el.removeChild(item));
  }
  await nextTick();
};

// 列是否显示逻辑
const columnIfShow = (column?: Partial<Omit<BasicColumn, "children">>) => {
  if (column) {
    if ("ifShow" in column) {
      if (typeof column.ifShow === "boolean") {
        return column.ifShow;
      } else if (column.ifShow) {
        return column.ifShow(column);
      }
    }
    return true;
  }
  return false;
};

// 获取数据列
const getTableColumns = () => {
  return table
    .getColumns({ ignoreIndex: true, ignoreAction: true })
    .filter((col) => columnIfShow(col));
};

// 设置列表列
const tableColumnsSet = (columns: BasicColumn[]) => {
  isInnerChange = true;
  table?.setColumns(columns);

  // 沿用逻辑
  const columnChangeParams: ColumnChangeParam[] = columns.map((col) => ({
    dataIndex: col.dataIndex ? col.dataIndex.toString() : "",
    fixed: col.fixed,
    visible: !col.defaultHidden,
  }));
  emit("columns-change", columnChangeParams);
};

// 列表列更新
const tableColumnsUpdate = () => {
  // 考虑了所有列
  const columns = cloneDeep(table.getColumns());

  // 从左 fixed 最一列开始排序（除了 序号列）
  let count = columns.filter(
    (o) =>
      o.flag !== INDEX_COLUMN_FLAG && (o.fixed === "left" || o.fixed === true),
  ).length;

  // 序号列提前
  if (isIndexColumnShow.value) {
    count++;
  }

  // 按 columnOptions 的排序 调整 table.getColumns() 的顺序和值
  for (const opt of columnOptions.value) {
    const colIdx = columns.findIndex((o) => o.dataIndex === opt.value);
    //
    if (colIdx > -1) {
      const target = columns[colIdx];
      target.defaultHidden = opt.column?.defaultHidden;
      target.fixed = opt.fixed;
      columns.splice(colIdx, 1);
      columns.splice(count++, 0, target); // 递增插入
    }
  }

  // 是否存在 action
  const actionIndex = columns.findIndex((o) => o.dataIndex === "action");
  if (actionIndex > -1) {
    const actionCol = columns.splice(actionIndex, 1);
    columns.push(actionCol[0]);
  }

  // 设置列表列
  tableColumnsSet(columns);
};

// 打开浮窗
const onOpenChange = async () => {
  await nextTick();

  if (columnOptionsRef.value) {
    // 注册排序实例
    const el = (columnOptionsRef.value as InstanceType<typeof Checkbox.Group>)
      .$el;
    Sortablejs.create(unref(el), {
      animation: 500,
      delay: 400,
      delayOnTouchOnly: true,
      handle: ".table-column-drag-icon ",
      dataIdAttr: "data-no",
      onEnd: (evt) => {
        const { oldIndex, newIndex } = evt;
        if (isNil(oldIndex) || isNil(newIndex) || oldIndex === newIndex) {
          return;
        }

        const options = cloneDeep(columnOptions.value);

        // 排序
        if (oldIndex > newIndex) {
          options.splice(newIndex, 0, options[oldIndex]);
          options.splice(oldIndex + 1, 1);
        } else {
          options.splice(newIndex + 1, 0, options[oldIndex]);
          options.splice(oldIndex, 1);
        }

        // 更新 列可选项
        columnOptions.value = options;

        // 列表列更新
        tableColumnsUpdate();
        // 更新列缓存
        props.cache && columnOptionsSave();
      },
    });
  }
};

// remove消失的列、push新出现的列
const diff = () => {
  if (typeof route.name === "string") {
    let cache = tableSettingStore.getColumns(route.name);
    if (cache) {
      // value、label是否一致
      if (
        JSON.stringify(
          columnOptions.value.map((o) => ({ value: o.value, label: o.label })),
        ) !==
        JSON.stringify(cache.map((o) => ({ value: o.value, label: o.label })))
      ) {
        const map = columnOptions.value.reduce((map, item) => {
          map[item.value] = item.label;
          return map;
        }, {});
        if (Array.isArray(cache)) {
          // remove消失的列
          cache = cache.filter((o) => map[o.value]);
          // 更新label
          cache.forEach((o) => {
            o.label = map[o.value];
          });
          const cacheKeys = cache.map((o) => o.value);
          // push新出现的列
          cache = cache.concat(
            columnOptions.value.filter((o) => !cacheKeys.includes(o.value)),
          );
          // 更新缓存
          tableSettingStore.setColumns(route.name, cache);
        }
      }
    }
  }
};

// 从缓存恢复
const restore = () => {
  if (typeof route.name === "string") {
    const isIndexColumnShowCache = tableSettingStore.getShowIndexColumn(
      route.name,
    );
    // 设置过才恢复
    if (typeof isIndexColumnShowCache === "boolean") {
      isIndexColumnShow.value =
        defaultIsIndexColumnShow && isIndexColumnShowCache;
    }

    const isRowSelectionShowCache = tableSettingStore.getShowRowSelection(
      route.name,
    );
    // 设置过才恢复
    if (typeof isRowSelectionShowCache === "boolean") {
      isRowSelectionShow.value =
        defaultIsRowSelectionShow && isRowSelectionShowCache;
    }
  }
  // 序号列更新
  onIndexColumnShowChange({
    target: { checked: isIndexColumnShow.value },
  } as CheckboxChangeEvent);
  // 选择列更新
  onRowSelectionShowChange({
    target: { checked: isRowSelectionShow.value },
  } as CheckboxChangeEvent);

  if (typeof route.name === "string") {
    const cache = tableSettingStore.getColumns(route.name);
    // 设置过才恢复
    if (Array.isArray(cache)) {
      columnOptions.value = cache;
    }
  }
};

// 从 列可选项 更新 已选列
const columnCheckedOptionsUpdate = () => {
  columnCheckedOptions.value = columnOptions.value
    .filter((o) => !o.column?.defaultHidden)
    .map((o) => o.value);
};
// 从 列可选项 更新 全选状态
const isColumnAllSelectedUpdate = () => {
  isColumnAllSelected.value =
    columnOptions.value.length === columnCheckedOptions.value.length;
};
// 更新 showIndexColumn
const showIndexColumnUpdate = (showIndexColumn) => {
  isInnerChange = true;
  table.setProps({
    showIndexColumn,
  });
};
// 更新 rowSelection
const showRowSelectionUpdate = (showRowSelection) => {
  isInnerChange = true;
  table.setProps({
    rowSelection: showRowSelection
      ? {
          ...omit(defaultRowSelection, ["selectedRowKeys"]),
          fixed: true,
        }
      : undefined,
  });
};

// 更新表单状态
const formUpdate = () => {
  // 从 列可选项 更新 已选列
  columnCheckedOptionsUpdate();

  // 从 列可选项 更新 全选状态
  isColumnAllSelectedUpdate();

  // 更新 showIndexColumn
  showIndexColumnUpdate(isIndexColumnShow.value);

  // 更新 showRowSelection
  showRowSelectionUpdate(isRowSelectionShow.value);

  // 列表列更新
  tableColumnsUpdate();
};

const init = async () => {
  if (!isRestored) {
    // 获取数据列
    const columns = getTableColumns();

    // 沿用逻辑
    table.setCacheColumns?.(columns);

    // 生成 默认值
    const options: ColumnOptionsType[] = [];
    for (const col of columns) {
      // 只缓存 string 类型的列
      options.push({
        label:
          typeof col.title === "string"
            ? col.title
            : col.customTitle === "string"
              ? col.customTitle
              : "",
        value:
          typeof col.dataIndex === "string"
            ? col.dataIndex
            : col.title === "string"
              ? col.title
              : "",
        column: {
          defaultHidden: col.defaultHidden,
        },
        fixed: col.fixed,
      });
    }

    // 默认值 缓存
    defaultIsIndexColumnShow =
      table.getBindValues.value.showIndexColumn || false;
    defaultRowSelection = table.getRowSelection();
    defaultIsRowSelectionShow = !!defaultRowSelection; // 设置了 rowSelection 才出现
    defaultColumnOptions = options;

    // 默认值 赋值
    isIndexColumnShow.value = defaultIsIndexColumnShow;
    isRowSelectionShow.value = defaultIsRowSelectionShow;
    columnOptions.value = cloneDeep(options);

    // remove消失的列、push新出现的列
    props.cache && diff();

    // 从缓存恢复
    props.cache && restore();

    // 更新表单状态
    formUpdate();

    isRestored = true;
  }
};

// 初始化
const once = async () => {
  // 仅执行一次
  await sortableFix();
  init();
};
once();

// 外部列改变
const getColumns = computed(() => {
  return table?.getColumns();
});
const getValues = computed(() => {
  return table?.getBindValues;
});

onMounted(() => {
  watch([getColumns, getValues], () => {
    if (!isInnerChange) {
      isRestored = false;
      console.log("onMounted isRestored");
      init();
    } else {
      isInnerChange = false;
    }
  });
});
</script>
<style lang="less">
@prefix-cls: ~"@{namespace}-basic-column-setting";

.table-column-drag-icon {
  margin: 0 5px;
  cursor: move;
}

.@{prefix-cls} {
  &__popover-title {
    display: flex;
    position: relative;
    align-items: center;
    justify-content: space-between;
  }

  &__check-item {
    display: flex;
    align-items: center;
    min-width: 100%;
    padding: 4px 16px 8px 0;

    .ant-checkbox-wrapper {
      width: 100%;

      &:hover {
        color: @primary-color;
      }
    }
  }

  &__fixed-left,
  &__fixed-right {
    color: rgb(0 0 0 / 45%);
    cursor: pointer;

    &.active,
    &:hover {
      color: @primary-color;
    }

    &.disabled {
      color: @disabled-color;
      cursor: not-allowed;
    }
  }

  &__fixed-right {
    transform: rotate(180deg);
  }

  &__column-list {
    svg {
      width: 1em !important;
      height: 1em !important;
    }

    .ant-popover-inner-content {
      // max-height: 360px;
      padding-right: 0;
      padding-left: 0;
      // overflow: auto;
    }

    .ant-checkbox-group {
      display: inline-block;
      width: 100%;
      min-width: 260px;
      // flex-wrap: wrap;
    }

    .scrollbar {
      height: 220px;
    }
  }
}
</style>
